#include "TestCube.h"
#include <RCGame.h>

TestCube::TestCube(void)
{
	Visible = true;
	Color = XMFLOAT4(1, 1, 1, 1);

	D3D11_INPUT_ELEMENT_DESC l[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};

	memcpy(layout, l, sizeof(D3D11_INPUT_ELEMENT_DESC)* ARRAYSIZE(l));

	PositionTexVertex v[] =
	{
		{ XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT2(0.0f, 0.0f) },
		{ XMFLOAT3(0.5f, 0.5f, -0.5f), XMFLOAT2(1.0f, 0.0f) },
		{ XMFLOAT3(0.5f, 0.5f, 0.5f), XMFLOAT2(1.0f, 1.0f) },
		{ XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT2(0.0f, 1.0f) },

		{ XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT2(0.0f, 0.0f) },
		{ XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT2(1.0f, 0.0f) },
		{ XMFLOAT3(0.5f, -0.5f, 0.5f), XMFLOAT2(1.0f, 1.0f) },
		{ XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT2(0.0f, 1.0f) },

		{ XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT2(0.0f, 0.0f) },
		{ XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT2(1.0f, 0.0f) },
		{ XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT2(1.0f, 1.0f) },
		{ XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT2(0.0f, 1.0f) },

		{ XMFLOAT3(0.5f, -0.5f, 0.5f), XMFLOAT2(0.0f, 0.0f) },
		{ XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT2(1.0f, 0.0f) },
		{ XMFLOAT3(0.5f, 0.5f, -0.5f), XMFLOAT2(1.0f, 1.0f) },
		{ XMFLOAT3(0.5f, 0.5f, 0.5f), XMFLOAT2(0.0f, 1.0f) },

		{ XMFLOAT3(-0.5f, -0.5f, -0.5f), XMFLOAT2(0.0f, 0.0f) },
		{ XMFLOAT3(0.5f, -0.5f, -0.5f), XMFLOAT2(1.0f, 0.0f) },
		{ XMFLOAT3(0.5f, 0.5f, -0.5f), XMFLOAT2(1.0f, 1.0f) },
		{ XMFLOAT3(-0.5f, 0.5f, -0.5f), XMFLOAT2(0.0f, 1.0f) },

		{ XMFLOAT3(-0.5f, -0.5f, 0.5f), XMFLOAT2(0.0f, 0.0f) },
		{ XMFLOAT3(0.5f, -0.5f, 0.5f), XMFLOAT2(1.0f, 0.0f) },
		{ XMFLOAT3(0.5f, 0.5f, 0.5f), XMFLOAT2(1.0f, 1.0f) },
		{ XMFLOAT3(-0.5f, 0.5f, 0.5f), XMFLOAT2(0.0f, 1.0f) },
	};

	memcpy(vertices, v, sizeof(PositionTexVertex)* ARRAYSIZE(v));

	WORD i[] =
	{
		3, 1, 0,
		2, 1, 3,

		6, 4, 5,
		7, 4, 6,

		11, 9, 8,
		10, 9, 11,

		14, 12, 13,
		15, 12, 14,

		19, 17, 16,
		18, 17, 19,

		22, 20, 21,
		23, 20, 22
	};

	memcpy(indices, i, sizeof(WORD)* ARRAYSIZE(i));
}

TestCube::~TestCube(void){ }

void TestCube::Initialize()
{
	ID3D11Device* device = pGame->getGraphicsDevice()->getDevice();
	// Compile the vertex shader
	ID3DBlob* pVSBlob = NULL;
	HRESULT hr = RCGame::CompileShaderFromFile(L"Tutorial07.fx", "VS", "vs_4_0", &pVSBlob);
	if (FAILED(hr))
	{
		MessageBox(NULL,
			L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK);
		return;
	}

	// Create the vertex shader
	hr = device->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &pVertexShader);
	if (FAILED(hr))
	{
		pVSBlob->Release();
		return;
	}

	UINT numElements = ARRAYSIZE(layout);

	// Create the input layout
	hr = device->CreateInputLayout(layout, numElements, pVSBlob->GetBufferPointer(),
		pVSBlob->GetBufferSize(), &pVertexLayout);
	pVSBlob->Release();

	// Compile the pixel shader
	ID3DBlob* pPSBlob = NULL;
	hr = RCGame::CompileShaderFromFile(L"Tutorial07.fx", "PS", "ps_4_0", &pPSBlob);
	if (FAILED(hr))
	{
		MessageBox(NULL,
			L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK);
		return;
	}

	// Create the pixel shader
	hr = device->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &pPixelShader);
	pPSBlob->Release();
	if (FAILED(hr))
		return;

	// Create vertex buffer
	D3D11_BUFFER_DESC bd;
	ZeroMemory(&bd, sizeof(bd));
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(PositionTexVertex)* 24;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory(&InitData, sizeof(InitData));
	InitData.pSysMem = vertices;
	hr = device->CreateBuffer(&bd, &InitData, &pVertexBuffer);
	if (FAILED(hr))
		return;

	// Build index
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(WORD)* 36;
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.CPUAccessFlags = 0;
	InitData.pSysMem = indices;
	hr = device->CreateBuffer(&bd, &InitData, &pIndexBuffer);
	if (FAILED(hr))
		return;

	// Create the constant buffers
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bd.ByteWidth = sizeof(CBChangeOnResize);
	hr = device->CreateBuffer(&bd, NULL, &pCBChangeOnResize);
	if (FAILED(hr))
		return;

	bd.ByteWidth = sizeof(CBChangesEveryFrame);
	hr = device->CreateBuffer(&bd, NULL, &pCBChangesEveryFrame);
	if (FAILED(hr))
		return;

	// Load the Texture
	hr = D3DX11CreateShaderResourceViewFromFile(device, L"seafloor.dds", NULL, NULL, &pTextureRV, NULL);
	if (FAILED(hr))
		return;

	// Create the sample state
	D3D11_SAMPLER_DESC sampDesc;
	ZeroMemory(&sampDesc, sizeof(sampDesc));
	sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
	sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
	sampDesc.MinLOD = 0;
	sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
	hr = device->CreateSamplerState(&sampDesc, &pSamplerLinear);
	if (FAILED(hr))
		return;
}

void TestCube::Draw(float time)
{
	ID3D11DeviceContext* context = pGame->getGraphicsDevice()->getDeviceContext();

	// Set the input layout
	context->IASetInputLayout(pVertexLayout);

	// Set vertex buffer
	UINT stride = sizeof(PositionTexVertex);
	UINT offset = 0;
	context->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);

	// Set index buffer
	context->IASetIndexBuffer(pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);

	// Set primitive topology
	context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);


	// Initialize the projection matrix    
	CBChangeOnResize cbChangesOnResize;
	cbChangesOnResize.mProjection = XMMatrixTranspose(camera->getProjection());
	context->UpdateSubresource(pCBChangeOnResize, 0, NULL, &cbChangesOnResize, 0, 0);

	//
	// Update variables that change once per frame
	//
	CBChangesEveryFrame cb;
	cb.mWorld = XMMatrixTranspose(getWorld());
	cb.vMeshColor = Color;
	cb.mView = XMMatrixTranspose(camera->getView());
	context->UpdateSubresource(pCBChangesEveryFrame, 0, NULL, &cb, 0, 0);

	// Render the cube
	context->VSSetShader(pVertexShader, NULL, 0);
	context->VSSetConstantBuffers(0, 1, &pCBChangeOnResize);
	context->VSSetConstantBuffers(1, 1, &pCBChangesEveryFrame);
	context->PSSetShader(pPixelShader, NULL, 0);
	context->PSSetConstantBuffers(1, 1, &pCBChangesEveryFrame);
	context->PSSetShaderResources(0, 1, &pTextureRV);
	context->PSSetSamplers(0, 1, &pSamplerLinear);
	context->DrawIndexed(36, 0, 0);

	ID3D11ShaderResourceView* texres = NULL;
	context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture
}

void TestCube::setCamera(IRCCamera* cam)
{
	camera = cam;
}



bool TestCube::getVisible()
{
	return Visible;
}
void TestCube::setVisible(bool value)
{
	Visible = value;
}